from openpyxl import load_workbook
import re 
from collections import OrderedDict    

class NumTypeError(Exception):
    '''
    '''

class DemDtcCfg(object):
    def __init__(self,DtcNum: str ='None',dtcName: str ='None',dtcEnCondGroupNum: int=0, debounce :str = 'C_1_1_1',eventList: list = [],agingCount:int = 40) -> None:
        self.DtcNum = DtcNum
        self.dtcName = dtcName
        self.dtcEnCondGroupNum = dtcEnCondGroupNum
        self.eventList = eventList
        self.agingCount = agingCount
        self.debounce = debounce

class DemDtcInfoClass(object):
    def __init__(self) -> None:
        self.dtcList = []
        self.DemEnCondGroupDict = OrderedDict()
        self.DemEnCondList = []
        self.DemDounceList = []

def searchDidInfo(filePath):
    excel = load_workbook(filePath)
    sheet = excel[excel.sheetnames[0]]
    DtcInfoList = []
    DemDtcInfo = DemDtcInfoClass()
    DemEnCondGroupKey = -1
    DemEnCondGroupDict = OrderedDict()
    DemEnCondList = []
    DemDounceList = []

    for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row, min_col=1, max_col=sheet.max_column):  
        try:
            dtcNum_high = hex(is_number(row[2].value,16))[2:].upper()
            dtcNum_low = hex(is_number(row[3].value,16))[2:].upper()
            if len(dtcNum_low) == 1:
                dtcNum_low = '0' + dtcNum_low
            dtcNum = dtcNum_high + dtcNum_low
        except ValueError:
            continue
        
        dtcName_List = row[4].value.split('\n')
        dtcName_List = dtcName_List[0].split()
        dtcName = ''
        if len(dtcName_List) > 1:
            for dtcName_ in dtcName_List:
                dtcName += dtcName_
                dtcName += '_'
            dtcName = dtcName[:-1] 
        else:
            dtcName = dtcName_List[0]

        if is_valid_c_variable_name(dtcName) == False:
            print('err')

        enableConditionList = []
        enableConditionList_ = row[5].value.split()
        for enableCondition in enableConditionList_:
            enableCondition = enableCondition.strip()
            if enableCondition == '':
                continue
            if is_valid_c_variable_name(enableCondition) == False:
                print('err')
            enableConditionList.append(enableCondition)
            if (enableCondition in DemEnCondList) == False:
                DemEnCondList.append(enableCondition)

        # check enableConditionList is in DemEnCondGroupDict or not
        ListInDict = False
        ListInDictKey = -1
        for DemEnCondGroup in DemEnCondGroupDict:
            if ListInDict == True:
                break
            ListInDictKey = ListInDictKey + 1

            if len(enableConditionList) == len(DemEnCondGroupDict[DemEnCondGroup]):
                num = 0
                for enableCondition in enableConditionList:
                    num = num + 1
                    if (enableCondition in DemEnCondGroupDict[DemEnCondGroup]) == False:
                        break
                    else:
                        if num == len(DemEnCondGroupDict[DemEnCondGroup]):
                            ListInDict = True
        if ListInDict == True:
            dtcEnCondGroupNum = ListInDictKey
        else:
            DemEnCondGroupKey = DemEnCondGroupKey + 1
            DemEnCondGroupDict[DemEnCondGroupKey] = enableConditionList
            dtcEnCondGroupNum = DemEnCondGroupKey

        debouce = enableConditionList_ = row[7].value
        #check debouce
        debouce_List = debouce.split('_')
        debounce_OK = False
        if len(debouce_List) == 4:
            try:
                is_number(debouce_List[1],10)
                is_number(debouce_List[2],10)

                if debouce_List[0] == 'C':
                    is_number(debouce_List[3],10)
                    debounce_OK = True
                if debouce_List[0] == 'T':
                    debounce_OK = True
            except ValueError:
                debounce_OK = False
        else:
            debounce_OK = False
        
        if debounce_OK == False:
            raise NumTypeError(f'''debouce格式不正确:{debouce},正确格式如下：
T_TimeBase ms: T_FailedTime_PassedTime_xx
CountBase: C_FailedCnt_PassedCnt_MaxCnt''')
        else:
            if debouce not in DemDounceList:
                DemDounceList.append(debouce)

        eventList = []
        if row[8].value == None:
            continue
        eventList_ = row[8].value.split('\n')
        for event in eventList_:
            event = event.strip()
            if event == '':
                continue
            if is_valid_c_variable_name(event) == False:
                raise NumTypeError('字符不合法')
            eventList.append(event)

        if len(eventList)<1:
            continue

        try:
            agingCount = is_number(row[6].value,10)
        except ValueError:
            continue
        
        DtcInfoList.append(DemDtcCfg(dtcNum,dtcName,dtcEnCondGroupNum,debouce,eventList,agingCount))

    DemDtcInfo.dtcList = DtcInfoList
    DemDtcInfo.DemEnCondGroupDict = DemEnCondGroupDict
    DemDtcInfo.DemEnCondList = DemEnCondList
    DemDtcInfo.DemDounceList = DemDounceList
    return DemDtcInfo

def is_valid_c_variable_name(name):  
    # 判断是否包含中文字符  
    if any(char for char in name if '\u4e00' <= char <= '\u9fff'):  
        return False  
      
    # 判断是否包含非法字符（C语言变量名只能包含字母、数字和下划线，且不能以数字开头）  
    if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', name):  
        return False  
      
    # 判断是否有乱码（这里只是简单检查是否为UTF-8编码的可打印字符）  
    try:  
        name.encode('utf-8').decode('utf-8')  
    except UnicodeDecodeError:  
        return False  
      
    return True

def is_number(s,type:int):
    if isinstance(s, str):
        if s.strip().startswith('0x'):
            s1 = s.strip().split('0x',1)
            if len(s1) == 2 and s1[1].isnumeric:
                s = int(s1[1],16)
                return s
            else:
                raise NumTypeError('不是数字')
        else:
            try:
                s = int(s,16)
                return s
            except ValueError:
                raise NumTypeError('不是数字')
    else:
        while 1:
            return int(str(s),type)
